<?php
/**
 * +----------------------------------------------------------------------
 * | summer framework
 * +----------------------------------------------------------------------
 * | Copyright (c) 2020 https://github.com/suframe/think-admin All rights reserved.
 * +----------------------------------------------------------------------
 * | Author: summer <806115620@qq.com>  2020/3/26 10:40
 * +----------------------------------------------------------------------
 */
declare (strict_types=1);

namespace app\mall\logic\order;

use app\mall\enum\OpUserEnum;
use app\mall\enum\OrderRefundEnum;
use app\mall\enum\OrderStatusEnum;
use app\mall\Events;
use app\mall\exceptions\BaseException;
use app\mall\exceptions\GoodsException;
use app\mall\exceptions\OrderException;
use app\mall\logic\GoodsLogic;
use app\mall\model\MallGoodsStock;
use app\mall\model\MallOrder;
use app\mall\model\MallOrderPay;
use app\mall\model\MallUser;
use app\mall\model\MallUserAddress;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Db;

class OrderUserLogic extends Base
{

    /**
     * 创建订单
     * @param MallUser $mallUser
     * @param MallGoodsStock $mallGoodsStock 购买商品
     * @param int $storeId 销售门店id
     * @param int $nums 购买数量
     * @param int $addressId 收货地址
     * @param int $shareUid 分享者
     * @param string $userDesc
     * @param array $acts 参与活动(优惠券,代金券，积分抵扣等)
     * @return string 订单号
     * @throws BaseException
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function create(
        MallUser $mallUser,
        MallGoodsStock $mallGoodsStock,
        int $storeId,
        int $nums,
        int $addressId,
        int $shareUid = 0,
        string $userDesc = '',
        array $acts = []
    ): string
    {
        if ($nums < 0) {
            GoodsException::throws(GoodsException::$userBuyNumError);
        }
        if ($mallGoodsStock->price < 0) {
            GoodsException::throws(GoodsException::$priceError);
        }
        //检查商品
        $goods = $mallGoodsStock->goods;
        if (!$goods->statusEnum->valid()) {
            GoodsException::throws(GoodsException::$notUpper);
        }
        //检查用户地址
        /** @var MallUserAddress $address */
        $address = MallUserAddress::where('uid', $mallUser->id)
            ->find($addressId);
        if (!$address) {
            OrderException::throws(OrderException::$addressError);
        }

        Db::startTrans();
        try {
            //扣除库存
            GoodsLogic::getInstance()->updateStock($mallGoodsStock, -$nums, '商品销售');
            //计算优惠
            if ($acts) {
                list($money, $originMoney, $discountMoney) = $this->actDeal($mallUser, $mallGoodsStock, $storeId, $nums, $acts);
            } else {
                $money = $originMoney = $mallGoodsStock->price * $nums;
                $discountMoney = 0;
            }
            //保存订单
            $info = [
                'sn' => $this->createSn(),
                'uid' => $mallUser->id,
                'store_id' => $storeId,
                'goods_id' => $goods->id,
                'address_id' => $address->id,
                'region_id' => $address->region_id,
                'goods_stock_id' => $mallGoodsStock->id,
                'share_uid' => $shareUid,
                'money' => $money,
                'nums' => $nums,
                'goods_price' => $mallGoodsStock->price,
                'origin_money' => $originMoney,
                'discount_money' => $discountMoney,
                'status' => OrderStatusEnum::NEW,
                'user_desc' => $userDesc,
            ];
            $order = new MallOrder();
            $order->save($info);
            Db::commit();
            return $order->sn;
        } catch (\Exception $e) {
            Db::rollback();
            throw $e;
        }
    }

    /**
     * 活动折扣计算
     * @param MallUser $mallUser
     * @param MallGoodsStock $mallGoodsStock
     * @param int $storeId
     * @param int $nums
     * @param array $acts
     * @return array
     */
    public function actDeal(
        MallUser $mallUser,
        MallGoodsStock $mallGoodsStock,
        int $storeId,
        int $nums,
        array $acts = []
    )
    {
        $originMoney = $mallGoodsStock->price * $nums;
        $discountMoney = 0;
        $money = $originMoney;
        //检查商品活动情况
        //检查用户参与条件
        //检查门店活动参与条件
        //计算打折价格
        //计算
        return [
            'money' => $money,
            'origin_money' => $originMoney,
            'discount_money' => $discountMoney,
        ];
    }

    /**
     * 支付结果，订单处理逻辑
     * @param MallOrder $mallOrder
     * @param MallOrderPay $mallOrderPay
     */
    public function afterPay(MallOrder $mallOrder, MallOrderPay $mallOrderPay)
    {

    }

    /**
     * 用户确认收货
     * @param MallOrder $mallOrder
     * @param MallUser $mallUser
     * @return bool
     */
    public function confirm(MallOrder $mallOrder, MallUser $mallUser): bool
    {

    }

    /**
     * 用户取消订单
     * @param MallOrder $mallOrder
     * @param MallUser $mallUser
     * @param string $reason
     * @return bool
     * @throws BaseException
     */
    public function cancel(MallOrder $mallOrder, MallUser $mallUser, string $reason = ''): bool
    {
        return $this->doCancel(
            $mallOrder,
            OpUserEnum::USER,
            $mallUser->id,
            "用户取消订单" . ($reason ? ':' . $reason : '')
        );
    }

    /**
     * 用户申请退款
     * @param MallOrder $mallOrder 退款订单
     * @param MallUser $mallUser 退款用户
     * @param string $desc 退款原因描述
     * @param array $images 申请退款原因图片
     * @return bool
     * @throws BaseException
     */
    public function refund(MallOrder $mallOrder, MallUser $mallUser, string $desc = '', array $images = []): bool
    {
        if (!$mallOrder->status_enum->canRefund()) {
            OrderException::throws(OrderException::$statusError);
        }
        if (!$mallOrder->userCanRefund()) {
            OrderException::throws(OrderException::$repeatApplyRefundError);
        }

        //修改订单申请状态
        $mallOrder->apply_refund = OrderRefundEnum::YES;
        $rs = $mallOrder->save();
        if (!$rs) {
            OrderException::throws(OrderException::$applyRefundFail);
        }
        $orderStatus = '申请时订单状态：' . $mallOrder->status_text . '.';
        $this->addLog(
            $mallOrder,
            OpUserEnum::USER,
            $mallUser->id,
            "申请退款," . $orderStatus . ($desc ? ':' . $desc : ''),
            $images
        );
        event(Events::ORDER_REFUND_APPLY, $mallOrder);
        return $rs;
    }

}